package org.zoomdev.zoom.aop.factory.impl;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.zoomdev.zoom.aop.Constructor;
import org.zoomdev.zoom.aop.factory.ConstructorFactory;
import org.zoomdev.zoom.aop.utils.AsmUtils;
import org.zoomdev.zoom.common.utils.Classes;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;

public final class ConstructorFactoryImpl extends AsmSingleMethodFactory<Constructor, Class<?>> implements ConstructorFactory {

    static Constructor MAP_FACTORY = () -> new LinkedHashMap<>();
    static Constructor TREEMAP_FACTORY = () -> new TreeMap();

    public ConstructorFactoryImpl(ClassLoader classLoader) {
        super(classLoader);
    }

    @Override
    protected Constructor createImpl(Class<?> param) {
        if (param == Map.class || param == HashMap.class) {
            return MAP_FACTORY;
        }

        if (param == TreeMap.class) {
            return TREEMAP_FACTORY;
        }

        if (param.getName().startsWith("java")) {
            return new ReflectConstructor(param);
        }


        return super.createImpl(param);
    }


    @Override
    protected byte[] createBytes(String className, Class<?> clazz) {
        String targetClassInternalName = Type.getInternalName(clazz);

        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);

        // 关键点：使用 AsmUtils.VERSION 确保生成 Java 8 字节码
        cw.visit(AsmUtils.VERSION, Opcodes.ACC_PUBLIC, className, null,
                "java/lang/Object", new String[]{Type.getInternalName(Constructor.class)});

        // 默认构造方法
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        // newInstance 方法
        mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
        mv.visitCode();
        mv.visitTypeInsn(Opcodes.NEW, targetClassInternalName);
        mv.visitInsn(Opcodes.DUP);
        mv.visitMethodInsn(Opcodes.INVOKESPECIAL, targetClassInternalName, "<init>", "()V", false);
        mv.visitInsn(Opcodes.ARETURN);
        mv.visitMaxs(2, 1);
        mv.visitEnd();

        cw.visitEnd();
        return cw.toByteArray();
    }


    @Override
    protected String getClassName(Class<?> param) {
        return (param.getName() + "$Constructor");
    }


    static class ReflectConstructor implements Constructor {
        private final Class type;

        ReflectConstructor(Class type) {
            this.type = type;
        }

        @Override
        public Object newInstance() {
            return Classes.newInstance(type);
        }
    }


}
